/*
 * Copyright (C) 2013 rdrrlabs gmail com,
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.rdrrlabs.example.timer2app.pub.ui;

import java.util.ArrayList;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.OnAccountsUpdateListener;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.rdrrlabs.example.liblabs.app.Bus;
import com.rdrrlabs.example.liblabs.app.Bus.Register;
import com.rdrrlabs.example.liblabs.app.IBusListener;
import com.rdrrlabs.example.timer2app.R;
import com.rdrrlabs.example.timer2app.core.BusConstants;
import com.rdrrlabs.example.timer2app.core.GAEHelper;
import com.rdrrlabs.example.timer2app.core.GAEHelper.State;
import com.rdrrlabs.example.timer2app.core.GlobalContext;

public class SignInDialog extends DialogFragment implements IBusListener {

    @SuppressWarnings("unused")
    private static final String TAG = SignInDialog.class.getSimpleName();

    static void showSignInDialog(FragmentActivity activity) {
        // based on http://developer.android.com/reference/android/app/DialogFragment.html
        FragmentManager fm = activity.getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        Fragment prev = fm.findFragmentByTag("dialog");
        if (prev != null) ft.remove(prev);
        ft.addToBackStack(null);
        SignInDialog df = new SignInDialog();
        df.show(ft, "dialog");
    }

    // -----------

    private static final int RESULT_SYNC_SETTINGS = Activity.RESULT_FIRST_USER + 1;
    private static final int MODE_SELECT_ACCOUNT = 0;
    private static final int MODE_AUTH_TOKEN = 1;

    private Button mBtnNext;
    private TextView mTextExplanation;
    private ListView mListView;
    private ProgressBar mProgress;
    private AccountManager mAccMan;
    private int mMode = MODE_SELECT_ACCOUNT;
    private OnAccountsUpdateListener mAccListener;
    private final State mState = new State();
    private final ArrayList<AccountWrapper> mAccountWrappers = new ArrayList<SignInDialog.AccountWrapper>();
    private Register<SignInDialog> mBusReg;

    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
        mAccMan = AccountManager.get(getActivity());
        mBusReg = Bus.register(this, GlobalContext.getContext().getBus());

        if (mAccListener == null) {
            mAccListener = new OnAccountsUpdateListener() {
                @Override
                public void onAccountsUpdated(Account[] accounts) {
                    updateAccountList();
                }
            };
        }

        mAccMan.addOnAccountsUpdatedListener(mAccListener, null/*handler*/, false/*updateImmediately*/);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mAccListener != null) mAccMan.removeOnAccountsUpdatedListener(mAccListener);
        mAccMan = null;
        mAccountWrappers.clear();
        mBusReg.deregister();
    }

    @Override
    public View onCreateView(
                    LayoutInflater inflater,
                    ViewGroup container,
                    Bundle state) {
        View root = inflater.inflate(R.layout.fragment_signin, container, false);

        getDialog().setTitle("Sign In");

        mBtnNext = (Button) root.findViewById(R.id.btnNext);
        mTextExplanation = (TextView) root.findViewById(R.id.txtExplanation);
        mListView = (ListView) root.findViewById(R.id.listAccounts);
        mListView.setEmptyView(root.findViewById(android.R.id.empty));
        mProgress = (ProgressBar) root.findViewById(R.id.progressBar1);

        displayList(true);

        Button btnCancel = (Button) root.findViewById(R.id.btnCancel);
        btnCancel.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // Dismiss the dialog.
                SignInDialog.this.dismiss();
            }
        });

        Button btnCreate = (Button) root.findViewById(android.R.id.empty);
        btnCreate.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
                //-- doesn't seem to work.
                //-- i.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { "com.google" });
                startActivityForResult(i, RESULT_SYNC_SETTINGS);
            }
        });


        mBtnNext.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Object o = v.getTag();
                if (o instanceof AccountWrapper) {
                    authenticateAccount(((AccountWrapper) o).getAccount());
                } else {
                    mListView.clearChoices();
                }
            }
        });

        setupAccountList(root);
        mBtnNext.setEnabled(false);

        return root;
    }

    private void displayList(boolean displayList) {
        mListView.setVisibility(displayList ? View.VISIBLE : View.GONE);
        mProgress.setVisibility(displayList ? View.GONE : View.VISIBLE);
        mProgress.setIndeterminate(!displayList);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == RESULT_SYNC_SETTINGS) {
            updateAccountList();
        }
    }

    private void setupAccountList(View root) {
        mListView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Object o = parent.getItemAtPosition(position);
                if (o instanceof AccountWrapper) {
                    mBtnNext.setEnabled(true);
                    mBtnNext.setTag(o);
                }
            }
        });
        updateAccountList();
    }

    private void updateAccountList() {
        if (mMode != MODE_SELECT_ACCOUNT) return;
        if (mListView == null) return; // this should not happen.

        mAccountWrappers.clear();
        for (Account account : mAccMan.getAccountsByType("com.google")) {
            mAccountWrappers.add(new AccountWrapper(account));
        }

        if (mAccountWrappers.isEmpty()) {
            mTextExplanation.setText("No Google accounts available.");  //FIXME res string
        } else {
            mTextExplanation.setText("Select a Google account:");  //FIXME res string
        }

        ArrayAdapter<AccountWrapper> adapter = new ArrayAdapter<AccountWrapper>(
                        getActivity(),
                        android.R.layout.simple_list_item_single_choice,
                        android.R.id.text1,
                        mAccountWrappers) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                return view;
            }
        };
        mListView.setAdapter(adapter);
        mListView.clearChoices();
    }

    /** Adapts an Account to be a list entry by providing its adequate string description. */
    private static class AccountWrapper {
        private final Account mAccount;

        public AccountWrapper(Account account) {
            mAccount = account;
        }

        public Account getAccount() {
            return mAccount;
        }

        @Override
        public String toString() {
            return mAccount.name;
        }
    }

    //-----

    private void authenticateAccount(Account account) {
        mMode = MODE_AUTH_TOKEN;
        mBtnNext.setEnabled(false);
        displayList(false);
        mTextExplanation.setText("Authenticating. This may take a few minutes.");

        GAEHelper ah = GlobalContext.getContext().getGAEHelper();
        mState.mAccountName = account.name;
        ah.getAuthToken(getActivity(), account, mState);
    }

    @Override
    public void onBusMessage(int what, Object object) {
        if (what == BusConstants.GAE_ACCOUNT_STATE_CHANGED &&
                object == mState) {
            mTextExplanation.post(new Runnable() {
                @Override
                public void run() {
                    String info = mState.mDetail;
                    if (info == null) {
                        switch(mState.mState) {
                        case State.NO_ACCOUNT:
                            // This shouldn't really happen here.
                            info = "Please select an account to sign-in.";
                            break;
                        case State.INVALID_ACCOUNT:
                            // This shouldn't really happen here.
                            info = "Invalid account, please select another account to sign-in.";
                            break;
                        case State.AUTH_TOKEN_FAILED:
                        case State.AUTH_COOKIE_FAILED:
                            info = "Failed to authenticate. Try again or change account.";
                            break;
                        case State.SUCCESS:
                            info = "Success";
                            break;
                        default:
                            info = "";
                        }
                    }
                    mTextExplanation.setText(info);

                    if (mState.mState != State.PENDING) {
                        mProgress.setIndeterminate(false);
                        mProgress.setProgress(mProgress.getMax());
                    }

                    if (mState.mState == State.SUCCESS) {
                        GAEHelper ah = GlobalContext.getContext().getGAEHelper();

                        ah.useAccount(getActivity(), mState.mAccountName, mState.mGAECookie);

                        // Auto-close
                        mTextExplanation.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                SignInDialog.this.dismiss();
                            }
                        }, 250 /*ms*/);
                    }

                }
            });
        }
    }
}
